package org.openhds.extensions;

import org.openhds.domain.util.CalendarAdapter;
import com.sun.codemodel.JAnnotationArrayMember;
import com.sun.codemodel.JAnnotationUse;
import com.sun.codemodel.JBlock;
import com.sun.codemodel.JCodeModel;
import com.sun.codemodel.JDefinedClass;
import com.sun.codemodel.JDocComment;
import com.sun.codemodel.JExpr;
import com.sun.codemodel.JFieldVar;
import com.sun.codemodel.JMethod;
import com.sun.codemodel.JMod;
import com.sun.codemodel.JVar;

public class DeathTemplateBuilder implements ExtensionTemplate {
	
	JCodeModel jCodeModel;
	boolean templateBuilt = false;
	
	DeathTemplateBuilder(JCodeModel jCodeModel) {
		this.jCodeModel = jCodeModel;
	}

	@Override
	public void buildTemplate(JDefinedClass jc) {
		
		JDocComment jDocComment = jc.javadoc();
		jDocComment.add("Generated by JCodeModel");
		
		jc._extends(org.openhds.domain.model.AuditableCollectedEntity.class);
		jc._implements(java.io.Serializable.class);
		
		buildClassAnnotations(jc);	
		buildFieldsAndMethods(jc);
		
		templateBuilt = true;
	}

	@Override
	public void buildFieldsAndMethods(JDefinedClass jc) {
		
		// serial uuid
		JFieldVar jfSerial = jc.field(JMod.PUBLIC | JMod.STATIC | JMod.FINAL, long.class, "serialVersionUID");
		jfSerial.init(JExpr.lit(-6644256636909420061L));
				
		// individual
		JFieldVar jfIndividual = jc.field(JMod.PRIVATE , org.openhds.domain.model.Individual.class, "individual");
		jfIndividual.annotate(org.openhds.domain.constraint.Searchable.class);
		jfIndividual.annotate(org.openhds.domain.constraint.CheckEntityNotVoided.class);
		jfIndividual.annotate(org.openhds.domain.constraint.CheckIndividualNotUnknown.class);
		JAnnotationUse jfIndividualCascade = jfIndividual.annotate(javax.persistence.ManyToOne.class);
		JAnnotationArrayMember cascadeArray = jfIndividualCascade.paramArray("cascade");
		cascadeArray.param(javax.persistence.CascadeType.MERGE);
		cascadeArray.param(javax.persistence.CascadeType.PERSIST);
		JAnnotationUse jaGroupHeadDesc = jfIndividual.annotate(org.openhds.domain.annotations.Description.class);
		jaGroupHeadDesc.param("description", "Individual who has died, identified by external id.");
		
		// getter
		JMethod jmgIndividual = jc.method(JMod.PUBLIC, org.openhds.domain.model.Individual.class, "getIndividual");
		JBlock jmgIndividualBlock = jmgIndividual.body();
		jmgIndividualBlock._return(jfIndividual);
		
		// setter
		JMethod jmsIndividual = jc.method(JMod.PUBLIC, void.class, "setIndividual");
		JVar jvarIndividual = jmsIndividual.param(org.openhds.domain.model.Individual.class, "indiv");
		JBlock jmsIndividualBlock = jmsIndividual.body();
		jmsIndividualBlock.assign(jfIndividual, jvarIndividual);
		
				
		// deathPlace
		JFieldVar jfDeathPlace = jc.field(JMod.PRIVATE , java.lang.String.class, "deathPlace");
		jfDeathPlace.annotate(org.openhds.domain.constraint.CheckFieldNotBlank.class);
		jfDeathPlace.annotate(org.openhds.domain.constraint.Searchable.class);
		JAnnotationUse jaDeathPlaceDesc = jfDeathPlace.annotate(org.openhds.domain.annotations.Description.class);
		jaDeathPlaceDesc.param("description", "Place where the death occurred.");
		
		// getter
		JMethod jmgDeathPlace = jc.method(JMod.PUBLIC, java.lang.String.class, "getDeathPlace");
		JBlock jmgDeathPlaceBlock = jmgDeathPlace.body();
		jmgDeathPlaceBlock._return(jfDeathPlace);
		
		// setter
		JMethod jmsDeathPlace = jc.method(JMod.PUBLIC, void.class, "setDeathPlace");
		JVar jvarDeathPlace = jmsDeathPlace.param(java.lang.String.class, "place");
		JBlock jmsDeathPlaceBlock = jmsDeathPlace.body();
		jmsDeathPlaceBlock.assign(jfDeathPlace, jvarDeathPlace);
		
		// deathCause
		JFieldVar jfDeathCause = jc.field(JMod.PRIVATE , java.lang.String.class, "deathCause");
		jfDeathCause.annotate(org.openhds.domain.constraint.CheckFieldNotBlank.class);
		jfDeathCause.annotate(org.openhds.domain.constraint.Searchable.class);
		JAnnotationUse jaDeathCauseDesc = jfDeathCause.annotate(org.openhds.domain.annotations.Description.class);
		jaDeathCauseDesc.param("description", "Cause of the death.");
		
		// getter
		JMethod jmgDeathCause = jc.method(JMod.PUBLIC, java.lang.String.class, "getDeathCause");
		JBlock jmgDeathCauseBlock = jmgDeathCause.body();
		jmgDeathCauseBlock._return(jfDeathCause);
		
		// setter
		JMethod jmsDeathCause = jc.method(JMod.PUBLIC, void.class, "setDeathCause");
		JVar jvarDeathCause = jmsDeathCause.param(java.lang.String.class, "cause");
		JBlock jmsDeathCauseBlock = jmsDeathCause.body();
		jmsDeathCauseBlock.assign(jfDeathCause, jvarDeathCause);
				
		// deathDate
		JFieldVar jfDeathDate = jc.field(JMod.PRIVATE , java.util.Calendar.class, "deathDate");
		JAnnotationUse jaDeathDate = jfDeathDate.annotate(javax.validation.constraints.NotNull.class);
		jaDeathDate.param("message", "You must provide a Death date");
		JAnnotationUse jaPast = jfDeathDate.annotate(javax.validation.constraints.Past.class);
		jaPast.param("message", "Death date should be in the past");
		JAnnotationUse jaTemporal = jfDeathDate.annotate(javax.persistence.Temporal.class);
		jaTemporal.param("value", javax.persistence.TemporalType.DATE);
		JAnnotationUse jaDeathDateDesc = jfDeathDate.annotate(org.openhds.domain.annotations.Description.class);
		jaDeathDateDesc.param("description", "Date of the Death.");
		
		// getter
		JMethod jmgDeathDate = jc.method(JMod.PUBLIC, java.util.Calendar.class, "getDeathDate");
		JAnnotationUse jaXmlDeathDate = jmgDeathDate.annotate(javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter.class);
		jaXmlDeathDate.param("value", CalendarAdapter.class);
		JBlock jmgDeathDateBlock = jmgDeathDate.body();
		jmgDeathDateBlock._return(jfDeathDate);
		
		// setter
		JMethod jmsDeathDate = jc.method(JMod.PUBLIC, void.class, "setDeathDate");
		JVar jvarDeathDate = jmsDeathDate.param(java.util.Calendar.class, "date");
		JBlock jmsDeathDateBlock = jmsDeathDate.body();
		jmsDeathDateBlock.assign(jfDeathDate, jvarDeathDate);
		
		// visitDeath
		JFieldVar jfVisitDeath = jc.field(JMod.PRIVATE , org.openhds.domain.model.Visit.class, "visitDeath");
		jfVisitDeath.annotate(org.openhds.domain.constraint.Searchable.class);
		JAnnotationUse jfVisitDeathCascade = jfVisitDeath.annotate(javax.persistence.ManyToOne.class);
		JAnnotationArrayMember visitDeathCascadeArray = jfVisitDeathCascade.paramArray("cascade");
		visitDeathCascadeArray.param(javax.persistence.CascadeType.MERGE);
		visitDeathCascadeArray.param(javax.persistence.CascadeType.PERSIST);
		JAnnotationUse jaVisitDeathDesc = jfVisitDeath.annotate(org.openhds.domain.annotations.Description.class);
		jaVisitDeathDesc.param("description", "Visit associated with the death, identified by external id.");
		
		// getter
		JMethod jmgVisitDeath = jc.method(JMod.PUBLIC, org.openhds.domain.model.Visit.class, "getVisitDeath");
		JBlock jmgVisitDeathBlock = jmgVisitDeath.body();
		jmgVisitDeathBlock._return(jfVisitDeath);
		
		// setter
		JMethod jmsVisitDeath = jc.method(JMod.PUBLIC, void.class, "setVisitDeath");
		JVar jvarVisitDeath = jmsVisitDeath.param(org.openhds.domain.model.Visit.class, "visit");
		JBlock jmsVisitDeathBlock = jmsVisitDeath.body();
		jmsVisitDeathBlock.assign(jfVisitDeath, jvarVisitDeath);
		
		// ageAtDeath
		JFieldVar jfAge = jc.field(JMod.PRIVATE , java.lang.Long.class, "ageAtDeath");
		JAnnotationUse jaAgeDesc = jfAge.annotate(org.openhds.domain.annotations.Description.class);
		jaAgeDesc.param("description", "Age of death in number of data.");
		
		// getter
		JMethod jmgAge = jc.method(JMod.PUBLIC, java.lang.Long.class, "getAgeAtDeath");
		JBlock jmgAgeBlock = jmgAge.body();
		jmgAgeBlock._return(jfAge);
		
		// setter
		JMethod jmsAge = jc.method(JMod.PUBLIC, void.class, "setAgeAtDeath");
		JVar jvarAge = jmsAge.param(java.lang.Long.class, "age");
		JBlock jmsAgeBlock = jmsAge.body();
		jmsAgeBlock.assign(jfAge, jvarAge);
	}

	@Override
	public void buildClassAnnotations(JDefinedClass jc) {
		
		// create Description annotation
		JAnnotationUse jad = jc.annotate(org.openhds.domain.annotations.Description.class);
		jad.param("description", "A Death represents the final event than an Individual can " +
		"have within the system. It consists of the Individual who has passed on, the " +
		"Visit associated with the Death, as well as descriptive information about the " +
		"occurrence, cause, and date of the death. If the Individual had any Residencies, " +
		"Relationships, or Memberships then they will become closed.");
				
		jc.annotate(org.openhds.domain.constraint.CheckDeathDateGreaterThanBirthDate.class);
		
		// create Entity annotation
		jc.annotate(javax.persistence.Entity.class);
		
		JAnnotationUse jat = jc.annotate(javax.persistence.Table.class);
		jat.param("name", "death");
		
		JAnnotationUse jxmlRoot = jc.annotate(javax.xml.bind.annotation.XmlRootElement.class);
		jxmlRoot.param("name", "death");
	}
}
